{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "interop.ipynb",
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S541ev7MvVe4",
        "colab_type": "text"
      },
      "source": [
        "# Interoperability\n",
        "\n",
        "Cirq has several features that allow the user to import/export from other quantum languages."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IhP-o7Faywza",
        "colab_type": "text"
      },
      "source": [
        "## Exporting and importing to JSON\n",
        "\n",
        "For storing circuits or for transfering them between collaborators, JSON can be a good choice.  Many objects in cirq can be serialized as JSON and then stored as a text file for transfer, storage, or for posterity.\n",
        "\n",
        "Any object that can be serialized, which includes circuits, moments, gates, operations, and many other cirq constructs, can be turned into JSON with the protocol `cirq.to_json(obj)`.  This will return a string that contains the serialized JSON.\n",
        "\n",
        "To take JSON and turn it back into a cirq object, the protocol `cirq.read_json` can be used.  This can take a python file or string filename as the first argument (`file_or_fn`) or can take a named `json_text` parameter to accept a string input.\n",
        "\n",
        "The following shows how to serialize and de-serialize a circuit."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "29xdO5hM8Zow",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 527
        },
        "outputId": "217de5e9-55db-4634-f754-f4c20c8a2033"
      },
      "source": [
        "import cirq\n",
        "\n",
        "# Example circuit\n",
        "circuit = cirq.Circuit(cirq.Z(cirq.GridQubit(1,1)))\n",
        "\n",
        "# Serialize to a JSON string\n",
        "json_string = cirq.to_json(circuit)\n",
        "print('JSON string:')\n",
        "print(json_string)\n",
        "print()\n",
        "\n",
        "# Now, read back the string into a cirq object\n",
        "# cirq.read_json can also read from a file\n",
        "new_circuit = cirq.read_json(json_text=json_string)\n",
        "\n",
        "print(f'Deserialized object of type: {type(new_circuit)}:')\n",
        "print(new_circuit)"
      ],
      "execution_count": 7,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "JSON string:\n",
            "{\n",
            "  \"cirq_type\": \"Circuit\",\n",
            "  \"moments\": [\n",
            "    {\n",
            "      \"cirq_type\": \"Moment\",\n",
            "      \"operations\": [\n",
            "        {\n",
            "          \"cirq_type\": \"SingleQubitPauliStringGateOperation\",\n",
            "          \"pauli\": {\n",
            "            \"cirq_type\": \"_PauliZ\",\n",
            "            \"exponent\": 1.0,\n",
            "            \"global_shift\": 0.0\n",
            "          },\n",
            "          \"qubit\": {\n",
            "            \"cirq_type\": \"GridQubit\",\n",
            "            \"row\": 1,\n",
            "            \"col\": 1\n",
            "          }\n",
            "        }\n",
            "      ]\n",
            "    }\n",
            "  ],\n",
            "  \"device\": {\n",
            "    \"cirq_type\": \"_UnconstrainedDevice\"\n",
            "  }\n",
            "}\n",
            "\n",
            "Deserialized object of type: <class 'cirq.circuits.circuit.Circuit'>:\n",
            "(1, 1): ───Z───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2ZyTfRAO7gI7",
        "colab_type": "text"
      },
      "source": [
        "### Advanced: Adding JSON compatibility for custom objects in cirq\n",
        "\n",
        "Most cirq objects come with serialization functionality added already.  If you are adding a custom object (such as a custom gate), you can still serialize the object, but you will need to add the magic functions `_json_dict_` and `_from_json_dict` to your object to do so.\n",
        "\n",
        "When de-serializing, in order to instantiate the correct object, you will also have to pass in a custom resolver.  This is a function that will take as input the serialized `cirq_type` string and output a constructable class.  See \n",
        "`cirq.protocols.json_serialization` for more details."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4TtHwvEwvSx3",
        "colab_type": "text"
      },
      "source": [
        "## Importing from OpenQASM\n",
        "\n",
        "The QASM importer is in an experimental state and currently only supports a subset of the full **OpenQASM spec**. Amongst others, classical control, arbitrary gate definitions, and even some of the gates that don't have a one-to-one representation in Cirq, are not yet supported. The functionality should be sufficient to import interesting quantum circuits. Error handling is very simple - on any lexical or syntactical error, a `QasmException` is raised.\n",
        "\n",
        "### Importing cirq.Circuit from QASM format\n",
        "\n",
        "Requirements: `ply`\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "TAkV3D6ryYdM",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "!pip install --quiet cirq\n",
        "!pip install --quiet ply==3.4"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "stVnkYjCveUl",
        "colab_type": "text"
      },
      "source": [
        "The following call will create a circuit defined by the input QASM string:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "LHFjG9trvhla",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 102
        },
        "outputId": "e79fd42a-b919-43b0-acbc-cda48e46dc67"
      },
      "source": [
        "from cirq.contrib.qasm_import import circuit_from_qasm\n",
        "circuit = circuit_from_qasm(\"\"\"\n",
        "    OPENQASM 2.0;\n",
        "    include \"qelib1.inc\";\n",
        "    qreg q[3];\n",
        "    creg meas[3];\n",
        "    h q;\n",
        "    measure q -> meas;\n",
        "    \"\"\")\n",
        "print(circuit)"
      ],
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "q_0: ───H───M('meas_0')───\n",
            "\n",
            "q_1: ───H───M('meas_1')───\n",
            "\n",
            "q_2: ───H───M('meas_2')───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UC4yfqFWvpyu",
        "colab_type": "text"
      },
      "source": [
        "#### Supported Control statements \n",
        "\n",
        "\n",
        "| Statement|Cirq support|Description|Example|\n",
        "|----| --------| --------| --------|\n",
        "|`OPENQASM 2.0;`| supported| Denotes a file in Open QASM format| OPENQASM 2.0;|\n",
        "|`qreg name[size];`| supported (see mapping qubits)| Declare a named register of qubits|`qreg q[5];`|\n",
        "|`creg name[size];`|supported (see mapping classical register to measurement keys)|  Declare a named register of bits|`creg c[5];`|\n",
        "|`include \"filename\";`| supported ONLY to include the standard \"qelib1.inc\" lib for compatibility| Open and parse another source file|`include \"qelib1.inc\";`|\n",
        "|`gate name(params) qargs;`|NOT supported| Declare a unitary gate||\n",
        "|`opaque name(params) qargs;`| NOT supported| Declare an opaque gate||\n",
        "|`// comment text`| supported|Comment a line of text|`// supported!`|\n",
        "|`U(θ,φ,λ) qubit/qreg;`|  supported| Apply built-in single qubit gate(s)|``U(pi/2,2*pi/3,0) q[0];``|\n",
        "|`CX qubit/qreg,qubit/qreg;`| supported|Apply built-in CNOT gate(s)|`CX q[0],q[1];`|\n",
        "|measure qubit/qreg|supported|Make measurements in Z basis||\n",
        "|`reset qubit/qreg;`| NOT supported|Prepare qubit(s) in <code>&#124;0></code>|`reset q[0];`| \n",
        "|`gatename(params) qargs;`|  supported for ONLY the supported subset of standard gates defined in \"qelib1.inc\"|Apply a user-defined unitary gate|`rz(pi/2) q[0];`|\n",
        "|`if(creg==int) qop;`| NOT supported| Conditionally apply quantum operation|`if(c==5) CX q[0],q[1];`|\n",
        "|`barrier qargs;`| NOT supported| Prevent transformations across this source line|`barrier q[0],q[1];`|\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3JUIezc4vrA7",
        "colab_type": "text"
      },
      "source": [
        "#### Gate conversion rules \n",
        "\n",
        "Note: The standard Quantum Experience standard gates are defined in ([qelib.inc](https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/qasm/libs/qelib1.inc)) \n",
        "based on the `U` and `CX` built-in instructions, and we could generate them dynamically. Instead, we chose to map them to native Cirq gates explicitly, which results in a more user-friendly circuit. \n",
        "\n",
        "| QE gates| Cirq translation| Notes|\n",
        "| --------| --------| --------|\n",
        "|`U(θ,φ,λ)` |`QasmUGate(θ,φ,λ)`|| \n",
        "|`CX` |`cirq.CX`|| \n",
        "|`u3(θ,φ,λ)`|`QasmUGate(θ,φ,λ)`||\n",
        "|`u2(φ,λ) = u3(π/2,φ,λ)`|`QasmUGate(π/2,φ,λ)`|| \n",
        "|`u1 (λ) = u3(0,0,λ)`| NOT supported || \n",
        "|`id`|`cirq.Identity`| one single-qubit Identity gate is created for each qubit if applied on a register|  \n",
        "|`u0(γ)`| NOT supported| this is the \"WAIT gate\" for length γ in QE| \n",
        "|`x`|`cirq.X`|| \n",
        "|`y`|`cirq.Y`|| \n",
        "|`z`|`cirq.Z`|| \n",
        "|`h`|`cirq.H`|| \n",
        "|`s`|`cirq.S`|| \n",
        "|`sdg`|``cirq.S**-1``|| \n",
        "|`t`|`cirq.T`|| \n",
        "|`tdg`|``cirq.T**-1``||\n",
        "|`rx(θ)`|`cirq.Rx(θ)`|| \n",
        "|`ry(θ)`|`cirq.Ry(θ)`|| \n",
        "|`rz(θ)`|`cirq.Rz(θ)`|| \n",
        "|`cx`|`cirq.CX`|| \n",
        "|`cy`|`cirq.ControlledGate(cirq.Y)`|| \n",
        "|`cz`|`cirq.CZ`|| \n",
        "|`ch`|`cirq.ControlledGate(cirq.H)`|| \n",
        "|`swap`|`cirq.SWAP`|| \n",
        "|`ccx`|`cirq.CCX`|| \n",
        "|`cswap`|`cirq.CSWAP`|| \n",
        "|`crz`| NOT supported || \n",
        "|`cu1`| NOT supported|| \n",
        "|`cu3`| NOT supported|| \n",
        "|`rzz`| NOT supported|| "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_o3T5f6Lvv7L",
        "colab_type": "text"
      },
      "source": [
        "#### Mapping quantum registers to qubits \n",
        "\n",
        "For a quantum register `qreg qfoo[n];` the QASM importer will create `cirq.NamedQubit`s named `qfoo_0`..`qfoo_<n-1>`. \n",
        "\n",
        "#### Mapping classical registers to measurement keys\n",
        "\n",
        "For a classical register `creg cbar[n];` the QASM importer will create measurement keys named `cbar_0`..`cbar_<n-1>`. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "btiW3GGrABgI",
        "colab_type": "text"
      },
      "source": [
        "## Importing from Quirk\n",
        "\n",
        "[Quirk](https://algassert.com/quirk) is a drag-and-drop quantum circuit simulator, great for manipulating and exploring small quantum circuits. Quirk's visual style gives a reasonably intuitive feel of what is happening, state displays update in real time as you change the circuit, and the general experience is fast and interactive.\n",
        "\n",
        "After constructing a circuit in Quirk, you can easily convert it to cirq using the URL generated.  Note that not all gates in Quirk are currently convertible."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "34PGwSRoo4FA",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 68
        },
        "outputId": "67f2227c-e5cd-4bfd-d9af-cd075d027d79"
      },
      "source": [
        "quirk_url = \"https://algassert.com/quirk#circuit={%22cols%22:[[%22H%22,%22H%22],[%22%E2%80%A2%22,%22X%22],[%22H%22,%22H%22]]}\"\n",
        "c= cirq.quirk_url_to_circuit(quirk_url)\n",
        "\n",
        "print(c)"
      ],
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "0: ───H───@───H───\n",
            "          │\n",
            "1: ───H───X───H───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ACX379_NqEFN",
        "colab_type": "text"
      },
      "source": [
        "You can also convert the JSON from the \"export\" button on the top bar of Quirk.  Note that you must parse the JSON string into a dictionary before passing it to the function:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "8Bu1R7p4qKp4",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 68
        },
        "outputId": "9fc86b0b-7329-4fab-8578-00877fdafd57"
      },
      "source": [
        "import json\n",
        "\n",
        "quirk_str=\"\"\"{\n",
        "  \"cols\": [\n",
        "    [\n",
        "      \"H\",\n",
        "      \"H\"\n",
        "    ],\n",
        "    [\n",
        "      \"•\",\n",
        "      \"X\"\n",
        "    ],\n",
        "    [\n",
        "      \"H\",\n",
        "      \"H\"\n",
        "    ]\n",
        "  ]\n",
        "}\"\"\"\n",
        "quirk_json=json.loads(quirk_str)\n",
        "c= cirq.quirk_json_to_circuit(quirk_json)\n",
        "\n",
        "print(c)"
      ],
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "0: ───H───@───H───\n",
            "          │\n",
            "1: ───H───X───H───\n"
          ],
          "name": "stdout"
        }
      ]
    }
  ]
}
